﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Windows.Forms;
using StockAnalysisModel;
using System.Threading;


namespace QQStockInfoReader
{
    public class AreaStockReader
    {
        //public string _formatStockAreaUrl = @"http://finance.qq.com/data/dctr_modules/ggsj.htm?t={i}&change_color_0";
        public string _formatStockAreaUrl = @"http://finance.qq.com/data/dctr_modules/ggsj.htm?t=1&change_color_0";
        public string _dataFormatCtlID = "ggsj_{0}_ctn";
        public string _areaTabFormatCtlID = "ykbar3_li{0}";
        private int _areaCount = 9;
        private int activedCount = 1;
        private WebBrowser _browser;
        private WebBrowser Browser
        {
            get
            {
                return _browser;
            }
            set
            {
                _browser = value;
            }
        }

        public HtmlDocument Document
        {
            get
            {
                return Browser.Document;
            }
        }
        private System.Threading.Timer timer;

        public AreaStockReader(WebBrowser browser)
        {
            this.Browser = browser;

        }

        public List<StockDailyInfo> Result { private set; get; }

        public bool IsComplete { private set; get; }

        public AreaStockReader(WebBrowser browser, string stockAreaUrl, string formatDataCtlID, string tabFormatCtlID, int areaCount)
        {
            this.Browser = browser;
            this._formatStockAreaUrl = stockAreaUrl;
            this._dataFormatCtlID = formatDataCtlID;
            this._areaTabFormatCtlID = tabFormatCtlID;
            this._areaCount = areaCount;

        }

        public void AysnRead()
        {
            if (timer != null)
            {
                timer.Change(Timeout.Infinite, Timeout.Infinite);
            }
            timer = new System.Threading.Timer((object state) => { ActiveAllTab(); }, null, 1000, Timeout.Infinite);
        }

        public void Read()
        {
            //ActiveAllTab();
            GetData();
        }

        protected void AysnGetData()
        {
            if (timer != null)
            {
                timer.Dispose();
            }
            //读取tab的数据 
            List<StockDailyInfo> result = new List<StockDailyInfo>();
            for (int i = 1; i <= this._areaCount; i++)
            {
                try
                {
                    result.AddRange(GetAreaData(i));
                }
                catch (Exception ex)
                {

                }
            }

            this.Result = result;
            IsComplete = true;
        }

        protected void GetData()
        {

            List<StockDailyInfo> result = new List<StockDailyInfo>();
            for (int i = 1; i <= this._areaCount; i++)
            {
                try
                {
                    result.AddRange(GetAreaData(i));
                }
                catch (Exception ex)
                {

                }
            }

            this.Result = result;
            IsComplete = true;
        }

        private void AysnActiveAllTab()
        {
            activedCount++;
            string areaTabID = string.Format(this._areaTabFormatCtlID, activedCount);
            this.InvokeAreaTabClickEvent(areaTabID);
            if (activedCount == this._areaCount + 1)
            {
                if (timer != null)
                {
                    timer.Change(Timeout.Infinite, Timeout.Infinite);
                }
                timer = new System.Threading.Timer((object state) => { GetData(); }, null, 2000, Timeout.Infinite);
            }
            else if (activedCount <= this._areaCount)
            {
                if (timer != null)
                {
                    timer.Change(Timeout.Infinite, Timeout.Infinite);
                }
                timer = new System.Threading.Timer((object state) => { ActiveAllTab(); }, null, 2000, Timeout.Infinite);
            }

        }

        private void ActiveAllTab()
        {
            for (int i = 1; i <= this._areaCount; i++)
            {
                string areaTabID = string.Format(this._areaTabFormatCtlID, i);
                this.InvokeAreaTabClickEvent(areaTabID);
            }
        }

        /// <summary>
        /// 数据格式形如：
        /// <div><table><tr><td></td><td></td><td></td><td></td></tr></table></div>
        /// </summary>
        /// <param name="dataCtlID"></param>
        /// <returns></returns>
        protected List<StockDailyInfo> GetAreaData(int areaIndex)
        {
            string areaTabID = string.Format(this._areaTabFormatCtlID, areaIndex);
            string areaFieldName = this.Document.GetElementById(areaTabID).InnerText.Trim(); List<StockDailyInfo> result = new List<StockDailyInfo>();
            //解析数据
            try
            {
                string areaDataCtlID = string.Format(this._dataFormatCtlID, areaIndex);
                HtmlElement divElement = _browser.Document.GetElementById(areaDataCtlID);
                //thead
                HtmlElement thead = divElement.GetElementsByTagName("thead")[0];
                HtmlElementCollection headTds = thead.GetElementsByTagName("td");
                string stockAreaName = headTds[2].InnerText.Trim();
                //tbody
                HtmlElement tbody = divElement.GetElementsByTagName("tbody")[0];
                HtmlElementCollection trs = tbody.GetElementsByTagName("tr");
                foreach (HtmlElement tr in trs)
                {
                    HtmlElementCollection tds = tr.GetElementsByTagName("td");
                    StockDailyInfo sdi = this.GetStockDailyInfo(tds);
                    sdi.AreaFiledName = areaFieldName;
                    sdi.StockAreaName = stockAreaName;
                    result.Add(sdi);
                }
            }
            catch (Exception ex)
            {

            }
            return result;
        }

        protected StockDailyInfo GetStockDailyInfo(HtmlElementCollection tdAreaStocks)
        {
            StockDailyInfo stkDlyInfo = new StockDailyInfo();
            stkDlyInfo.StockID = tdAreaStocks[0].InnerText;
            stkDlyInfo.StockName = tdAreaStocks[1].InnerText;
            stkDlyInfo.StockAreaValue = decimal.Parse(tdAreaStocks[2].InnerText.Trim());
            stkDlyInfo.EndValue = decimal.Parse(tdAreaStocks[3].InnerText.Trim());
            stkDlyInfo.ShockAmount = decimal.Parse(tdAreaStocks[4].InnerText.Trim().TrimEnd('%'));
            stkDlyInfo.StartValue = decimal.Parse(tdAreaStocks[6].InnerText.Trim());
            stkDlyInfo.MaxValue = decimal.Parse(tdAreaStocks[7].InnerText.Trim());
            stkDlyInfo.MinValue = decimal.Parse(tdAreaStocks[8].InnerText.Trim());
            stkDlyInfo.Volume = decimal.Parse(tdAreaStocks[9].InnerText.Trim());
            stkDlyInfo.Turnover = decimal.Parse(tdAreaStocks[10].InnerText.Trim());
            stkDlyInfo.IsIncrease = (stkDlyInfo.EndValue - stkDlyInfo.StartValue) >= 0;
            stkDlyInfo.RecordDate = DateTime.Now;
            return stkDlyInfo;

        }

        /// <summary>
        /// 调用js,激活各个tab
        /// </summary>
        /// <param name="areaTabID"></param>
        protected void InvokeAreaTabClickEvent(string areaTabID)
        {
            HtmlElement tabArea = this.Document.GetElementById(areaTabID);
            tabArea.InvokeMember("click");

        }

        /// <summary>
        /// 调用js,激活各个tab
        /// </summary>
        /// <param name="areaTabID"></param>
        public void InvokeAreaTabClickEventByHand()
        {
            this.activedCount++;

            if (this.activedCount > this._areaCount)
                return;

            string areaTabID = string.Format(this._areaTabFormatCtlID, activedCount);
            HtmlElement tabArea = this.Document.GetElementById(areaTabID);
            tabArea.InvokeMember("click");

        }

        private void Open()
        {
            _browser.Navigate(this._formatStockAreaUrl);
        }

        private static IEnumerable<string> _areaFilds = new string[] { "累计涨幅", "连续上涨", "换手率统计", "大卖单频现", "大买单频现", "成交突增", "远离成本股", "量增价涨" };
        public static IEnumerable<string> GetAreaFileds()
        {
            return _areaFilds;
        }

        public static DataTable ConvertOjbsToDataTable(IEnumerable<StockDailyInfo> dataSource, string[] ares, int startValueIndex = 11)
        {

            //股票ID分组
            var infoGrpsByID = (from info in dataSource
                                group info by info.StockID.Trim()
                                    into infoGrpByID
                                    select infoGrpByID).ToList();
            //各股票area分组
            var infogGrpsByArea = (from info in dataSource
                                   group info by info.StockAreaName.Trim()
                                       into infoGrpByArea
                                       select infoGrpByArea).ToList();

            var fileds = from grp in infogGrpsByArea
                         select grp.First().StockAreaName;

            DataTable dt = CreateSchemeTable(fileds.ToArray());

            //先绑定各股票
            foreach (var infoGrp in infoGrpsByID)
            {
                StockDailyInfo info = infoGrp.First();
                DataRow dr = dt.NewRow();
                BindValueToDataRow(dr, info);
                dt.Rows.Add(dr);
            }

            foreach (var infoGrp in infogGrpsByArea)
            {
                foreach (StockDailyInfo info in infoGrp)
                {
                    if (info == null)
                    {
                        continue;
                    }
                    DataRow dr = dt.AsEnumerable().First(o => o["股票代码"].ToString() == info.StockID);
                    if (info.StockAreaValue.HasValue && info.StockAreaValue.ToString().Length > 0)
                    {
                        dr[info.StockAreaName] = info.StockAreaValue;
                    }
                    else
                    {
                        dt.Rows.Remove(dr);
                    }
                }
            }

            //过滤不同时具有值的列
            List<DataRow> lstEmptyDr = new List<DataRow>();
            int range = dt.Columns.Count;
            foreach (DataRow dr in dt.Rows)
            {
                for (int i = startValueIndex; i < range; i++)
                {
                    if (dr[i] == DBNull.Value || dr[i].ToString().Length < 1)
                    {
                        lstEmptyDr.Add(dr);
                        break;
                    }
                }
            }

            foreach (DataRow dr in lstEmptyDr)
            {
                dt.Rows.Remove(dr);
            }

            //序号赋值
            int sno = 0;
            foreach (DataRow dr in dt.Rows)
            {
                dr[0] = ++sno;
            }
            return dt;
        }

        private static void BindValueToDataRow(DataRow dr, StockDailyInfo info)
        {
            dr["股票代码"] = info.StockID;
            dr["股票名称"] = info.StockName;
            dr["最大值"] = info.MaxValue;
            dr["最小值"] = info.MinValue;
            dr["开盘"] = info.StartValue;
            dr["收盘"] = info.EndValue;
            dr["振幅"] = info.ShockAmount;
            dr["成交量"] = info.Volume;
            dr["换手率"] = info.Turnover;
            dr["涨"] = info.IsIncrease;
            dr["日期"] = info.RecordDate.Value.Date;

        }

        private static DataTable CreateSchemeTable(string[] fields)
        {
            DataTable dt = new DataTable();

            #region 固定字段
            DataColumn dc = new DataColumn();
            dc.ColumnName = "序号";
            dc.DataType = typeof(int);
            dt.Columns.Add(dc);
            dc = new DataColumn();
            dc.ColumnName = "股票代码";
            dc.DataType = typeof(string);
            dt.Columns.Add(dc);
            dc = new DataColumn();
            dc.ColumnName = "股票名称";
            dc.DataType = typeof(string);
            dt.Columns.Add(dc);


            dc = new DataColumn();
            dc.ColumnName = "开盘";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "收盘";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "振幅";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "成交量";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "换手率";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);


            dc = new DataColumn();
            dc.ColumnName = "最大值";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "最小值";
            dc.DataType = typeof(decimal);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "涨";
            dc.DataType = typeof(bool);
            dt.Columns.Add(dc);

            dc = new DataColumn();
            dc.ColumnName = "日期";
            dc.DataType = typeof(DateTime);
            dt.Columns.Add(dc);
            #endregion

            foreach (string area in fields)
            {
                dc = new DataColumn();
                dc.ColumnName = area;
                dc.DataType = typeof(string);
                dt.Columns.Add(dc);
            }

            return dt;
        }

    }
}
